package fr.doume.jna.jna;

//import com.sun.jna.Native;
//import com.sun.jna.platform.win32.WinNT;
//import com.sun.jna.NativeLong;
import com.sun.jna.IntegerType;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;

import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;

import com.sun.jna.platform.win32.Sspi;

public abstract class Sspibis {	

    /**
	 * Security handle.
	 */
	public static class SecHandle extends Structure {		
		public ULONG_PTR dwLower;
		public ULONG_PTR dwUpper;

		public static class ByReference extends SecHandle implements Structure.ByReference {

		}
		

		/**
		 * An empty SecHandle.
		 */
		public SecHandle() {
			dwLower.setValue(0);
			dwUpper.setValue(0);
		}
		
		/**
		*
		*/
		public SecHandle(long lower, long uppper)
		{
      dwLower.setValue(lower);
			dwUpper.setValue(uppper);
		}
		
		/**
		 * Returns true if the handle is NULL.
		 * @return
		 *  True if NULL, False otherwise.
		 */
		public boolean isNull() {
      return (dwLower.longValue() == 0 && dwUpper.longValue() == 0);
		}
		
		public boolean isInvalid()
		{
		  long lower = dwLower.longValue();
		  long upper = dwUpper.longValue();
		  return (      (lower == 0 && upper == 0) || (lower == -1 && upper == -1)     );
		}
		
		public long getLower()
		{
		  return dwLower.longValue();
		}
		
		public long getUpper()
		{
		  return dwUpper.longValue();
		}
	}
	
    /**
	 * Credentials handle.
	 */
	public static class CredHandle extends SecHandle {
		public CredHandle(long lower, long uppper)
		{
      dwLower.setValue(lower);
			dwUpper.setValue(uppper);
		}
		
	}
	
    /**
	 * Security context handle.
	 */
	public static class CtxtHandle extends SecHandle {		
		public CtxtHandle(long lower, long uppper)
		{
      dwLower.setValue(lower);
			dwUpper.setValue(uppper);
		}

	}

  public static class SecBuffer extends Structure {
  
      /**
       * A ByReference SecBuffer.
       */
    public static class ByReference extends SecBuffer implements Structure.ByReference {
          /**
           * Create a SECBUFFER_EMPTY SecBuffer.
           */
          public ByReference() {
        
          }
      
          /**
           * Create a SecBuffer of a given type and size.
           * @param type
           *  Buffer type, one of SECBUFFER_EMTPY, etc.
           * @param size
           *  Buffer size, eg. MAX_TOKEN_SIZE.
           */
          public ByReference(int type, int size) {
              super(type, size);
          }

          public ByReference(int type, byte[] token) {
              super(type, token);
          }
    
          /**
           * Get buffer bytes.
           * @return
           *  Raw buffer bytes.
           */
          public byte[] getBytes() {
              return super.getBytes();
          }
    }
  
      /**
       * Specifies the size, in bytes, of the buffer pointed to by the pvBuffer member.
       */
      public NativeLong cbBuffer;
      /**
       * Bit flags that indicate the type of buffer. Must be one of the values of 
       * the SecBufferType enumeration.
       */
      public NativeLong BufferType;
      /**
       * A pointer to a buffer.
       */
      public Pointer pvBuffer;
    
      /**
       * Create a new SECBUFFER_EMPTY buffer.
       */
      public SecBuffer() {
          cbBuffer = new NativeLong(0);
          pvBuffer = null;
          BufferType = new NativeLong(Sspi.SECBUFFER_EMPTY);
      }
    
      /**
       * Create a SecBuffer of a given type and size.
       * @param type
       *  Buffer type, one of SECBUFFER_EMTPY, etc.
       * @param size
       *  Buffer size, eg. MAX_TOKEN_SIZE.
       */
      public SecBuffer(int type, int size) {
          cbBuffer = new NativeLong(size);	    	
          pvBuffer = new Memory(size);
          BufferType = new NativeLong(type);
          //allocateMemory();
      }
    
      /**
       * Create a SecBuffer of a given type with initial data.
       * @param type
       *  Buffer type, one of SECBUFFER_EMTPY, etc.
       * @param token
       *  Existing token.
       */
      public SecBuffer(int type, byte[] token) {
          cbBuffer = new NativeLong(token.length);	    	
          pvBuffer = new Memory(token.length);
          pvBuffer.write(0, token, 0, token.length);
          BufferType = new NativeLong(type);
          //allocateMemory();
      }
    
      /**
       * Get buffer bytes.
       * @return
       *  Raw buffer bytes.
       */
      public byte[] getBytes() {
          return pvBuffer.getByteArray(0, cbBuffer.intValue());
      }
  }

  public static class SecBufferDesc extends Structure {
      
      /**
       * Version number.
       */
      public NativeLong ulVersion;
      /**
       * Number of buffers.
       */
      public NativeLong cBuffers;
      /**
       * Pointer to array of buffers.
       */
      public SecBuffer.ByReference pBuffers;
      //public SecBuffer.ByReference[] pBuffers;


      /**
       * Create a new SecBufferDesc with one SECBUFFER_EMPTY buffer.
       */
      public SecBufferDesc() {
          ulVersion = new NativeLong(Sspi.SECBUFFER_VERSION);
          cBuffers = new NativeLong(1);
          pBuffers = new SecBuffer.ByReference();
          //SecBuffer.ByReference secBuffer = new SecBuffer.ByReference();
          //pBuffers = (SecBuffer.ByReference[]) secBuffer.toArray(1);
          //allocateMemory();
      }
    
      /**
       * Create a new SecBufferDesc with initial data.
       * @param type
       *  Token type.
       * @param token
       *  Initial token data.
       */
      public SecBufferDesc(int type, byte[] token) {
          ulVersion = new NativeLong(Sspi.SECBUFFER_VERSION);
          cBuffers = new NativeLong(1);
          pBuffers = new SecBuffer.ByReference(type, token);
          //SecBuffer.ByReference secBuffer = new SecBuffer.ByReference(type, token);
          //pBuffers = (SecBuffer.ByReference[]) secBuffer.toArray(1);
          //allocateMemory();	    	
      }
    
      /**
       * Create a new SecBufferDesc with one SecBuffer of a given type and size.
       * @param type
       * @param tokenSize
       */
      public SecBufferDesc(int type, int tokenSize) {
          ulVersion = new NativeLong(Sspi.SECBUFFER_VERSION);
          cBuffers = new NativeLong(1);
          pBuffers = new SecBuffer.ByReference(type, tokenSize);
          //SecBuffer.ByReference secBuffer = new SecBuffer.ByReference(type, tokenSize);
          //pBuffers = (SecBuffer.ByReference[]) secBuffer.toArray(1);
          //allocateMemory();
      }	    	
    
      public byte[] getBytes() {
          if (pBuffers == null || cBuffers == null) {
              throw new RuntimeException("pBuffers | cBuffers");
          }
          if (cBuffers.intValue() == 1) {
              return pBuffers.getBytes();
              //return pBuffers[0].getBytes();
          }	    	
          throw new RuntimeException("cBuffers > 1");
      }
  }

}
